home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
toswinsc.zoo
/
menu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-27
|
15KB
|
721 lines
/*
* Copyright 1992 Eric R. Smith. All rights reserved.
* Redistribution is permitted only if the distribution
* is not for profit, and only if all documentation
* (including, in particular, the file "copying")
* is included in the distribution in unmodified form.
* THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
* EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
* RISK.
*/
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <osbind.h>
#include <ctype.h>
#include <keycodes.h>
#include "xgem.h"
char *about_string = "About...";
char *desk_string = "TOSWIN";
void (*about_func)() = 0;
/* local variables */
static MENU *curmenu = 0; /* currently displayed menu */
static MENU *deskmenu = 0; /* the whole menu bar, include " Desk " */
static OBJECT *menuobj = 0; /* menu object for the displayed menu */
/*
* Create a menu with the given title. Under GEM, we automatically
* add a space before and after the title, for aesthetics. (This is
* done in fixmenu.)
*/
MENU *
create_menu(title)
const char *title;
{
MENU *m;
m = malloc(sizeof(MENU));
if (!m) return m;
m->next = 0;
m->title = strdup(title);
m->width = 0;
m->contents = 0;
m->index = 0;
return m;
}
/*
* Destroy a menu, freeing any memory allocated for it.
*/
void
destroy_menu(menu)
MENU *menu;
{
MENU *m;
ENTRY *e;
if (curmenu && menu == curmenu) {
hide_menu();
}
while (menu) {
m = menu; menu = m->next;
while ((e = m->contents)) {
m->contents = e->next;
free(e->entry);
free(e);
}
free(m);
}
}
/*
* Add a new entry to a menu. We automatically add 2 spaces before and
* 2 after the menu entry string, for aesthetics, in fixmenu, and
* any special key symbols are also placed there; so the user doesn't
* need to worry about these details.
* NOTE: the string given as `entry' need not remain around permanently;
* we duplicate it just to be on the safe side.
* Returns: the newly added entry, or NULL on failure.
*/
ENTRY *
add_entry( m, entry, f, arg, key, state)
MENU *m;
char *entry;
void (*f)();
void *arg;
int key, state;
{
ENTRY *e, **ep;
e = malloc(sizeof(ENTRY));
if (!e) return 0;
ep = &m->contents;
while (*ep) {
ep = &((*ep)->next);
}
*ep = e;
e->next = 0;
e->entry = strdup(entry);
e->func = f;
e->arg = arg;
e->state = state;
e->keycode = key;
e->index = 0;
return e;
}
/* calculate the length of an entry; this is:
* 2 (leading blanks) + strlen(e->entry) + 2 (trailing blanks) +
* (optional) some number of bytes for any key symbols
*/
#define MAXKEYSYMLEN 4
int
entrylen(e)
ENTRY *e;
{
return 4 + strlen(e->entry) + (e->keycode ? 1 + strlen(UNALT(e->keycode)) :
0);
}
/*
* make a string representing a menu entry
*/
char *
entrystr(e, wide)
ENTRY *e;
int wide;
{
int i, n;
char *s, *ret, c;
n = wide + 1;
ret = malloc(n);
if (!ret) return 0;
i = 2;
c = '-';
for (s = e->entry; *s; s++) {
ret[i++] = *s;
if (*s != '-') c = ' ';
if (i == n) break;
}
ret[0] = c; ret[1] = c; /* leading blanks or dashes */
while (i < n-1)
ret[i++] = c; /* trailing blanks or dashes */
ret[n-1] = 0;
/* special case for '-----' type strings */
if (c == '-') {
return ret;
}
/* special symbols for keyboard equivalents */
if (e->keycode) {
s = UNALT(e->keycode);
i = (n-2) - strlen(s); /* right justify, trailing blank */
if (i > 3) {
while (*s)
ret[i++] = *s++;
}
}
return ret;
}
static OBJECT *
fixmenu( bar )
MENU *bar;
{
OBJECT *obj;
int i, wide, y, place;
int numobjects, num_titles, num_entries;
int menubox;
MENU *m; ENTRY *e;
char *s;
numobjects = 4; /* all menu bars needs some invisible boxes */
num_titles = 0;
/* count up the number of objects necessary */
for (m = bar; m; m = m->next) {
num_titles++;
numobjects++; /* for the title */
numobjects++; /* for the menu box */
for (e = m->contents; e; e = e->next) {
numobjects++; /* for the entry */
}
}
obj = malloc(numobjects * sizeof(OBJECT));
if (!obj) return obj;
/* now we create the various objects we need */
/* first, the root menu bar object */
obj[0].ob_next = -1;
obj[0].ob_head = 1;
obj[0].ob_tail = num_titles + 3;
obj[0].ob_type = G_IBOX;
obj[0].ob_flags = NONE; obj[0].ob_state = NORMAL;
obj[0].ob_spec = 0L;
obj[0].ob_x = 0; obj[0].ob_y = 0;
obj[0].ob_width = 90; obj[0].ob_height = 25;
/* now the menu bar box itself */
obj[1].ob_next = obj[0].ob_tail;
obj[1].ob_head = 2;
obj[1].ob_tail = 2;
obj[1].ob_type = G_BOX;
obj[1].ob_flags = NONE; obj[1].ob_state = NORMAL;
obj[1].ob_spec = 0x00001100L;
obj[1].ob_x = 0; obj[1].ob_y = 0;
obj[1].ob_width = 90; obj[1].ob_height = 513;
obj[2].ob_next = 1;
obj[2].ob_head = 3;
obj[2].ob_tail = 2 + num_titles;
obj[2].ob_type = G_IBOX;
obj[2].ob_flags = NONE; obj[2].ob_state = NORMAL;
obj[2].ob_spec = 0L;
obj[2].ob_x = 2; obj[2].ob_y = 0;
obj[2].ob_width = 0; /* will be adjusted later */
obj[2].ob_height = 769;
i = 3;
for (m = bar; m; m = m->next) {
m->index = i;
obj[i].ob_next = (m->next == 0) ? 2 : i+1;
obj[i].ob_head = obj[i].ob_tail = -1;
obj[i].ob_type = G_TITLE;
obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
obj[i].ob_width = strlen(m->title) + 2;
s = malloc(obj[i].ob_width + 1);
if (!s) return NULL;
s[0] = ' ';
strcpy(s+1, m->title);
strcat(s, " ");
obj[i].ob_spec = (long)s;
obj[i].ob_height = 769;
obj[i].ob_x = obj[2].ob_width;
obj[2].ob_width += obj[i].ob_width;
obj[i].ob_y = 0;
i++;
}
obj[i].ob_next = 0;
obj[i].ob_head = i+1;
obj[i].ob_tail = 0; /* to be adjusted later */
menubox = i;
obj[i].ob_type = G_IBOX;
obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
obj[i].ob_spec = 0L;
obj[i].ob_x = 0; obj[i].ob_y = 769;
obj[i].ob_width = 80; obj[i].ob_height = 19;
i++;
/* now, for each menu we calculate the number of entries and
* the size of the necessary box
*/
place = 2;
for (m = bar; m; m = m->next) {
int box;
box = i;
num_entries = wide = 0;
for(e = m->contents; e; e = e->next) {
num_entries++;
if (m == deskmenu) {
if (strlen(e->entry) > wide)
wide = strlen(e->entry);
} else {
if (entrylen(e) > wide)
wide = entrylen(e);
}
}
if (m->next)
obj[i].ob_next = i + num_entries + 1;
else {
obj[i].ob_next = menubox;
obj[menubox].ob_tail = i;
}
obj[i].ob_head = i+1;
obj[i].ob_tail = i + num_entries;
obj[i].ob_type = G_BOX;
obj[i].ob_flags = NONE; obj[i].ob_state = NORMAL;
obj[i].ob_spec = 0x00ff1100L;
obj[i].ob_x = place; obj[i].ob_y = 0;
place += strlen(m->title)+2;
obj[i].ob_width = wide; obj[i].ob_height = num_entries;
i++;
y = 0;
for (e = m->contents; e; e = e->next) {
e->index = i;
obj[i].ob_next = (e->next) ? i+1 : box;
obj[i].ob_head = obj[i].ob_tail = -1;
obj[i].ob_type = G_STRING;
obj[i].ob_flags = NONE;
obj[i].ob_state = e->state;
/* Do NOT malloc the strings for the Desk menu, or else there
* will be a memory leak!
*/
if (m != deskmenu)
s = entrystr(e, wide);
else {
s = e->entry;
}
if (!s) return NULL;
obj[i].ob_spec = (long)s;
obj[i].ob_x = 0; obj[i].ob_y = y++;
obj[i].ob_width = wide; obj[i].ob_height = 1;
i++;
}
}
obj[i-1].ob_flags = LASTOB;
/* now, fix the object tree up */
for (i = 0; i < numobjects; i++)
rsrc_obfix(obj, i);
return obj;
}
void
handle_menu(title, index)
int title, index;
{
MENU *m;
ENTRY *e;
for (m = deskmenu; m; m = m->next) {
if (m->index == title) break;
}
if (m) {
for (e = m->contents; e; e = e->next) {
if (e->index == index) {
(*e->func)(e->arg);
menu_tnormal(menuobj, title, 1);
return;
}
}
}
/* strange. Let's just punt and return */
}
/*
* erase menu currently on screen (if one exists), and frees the memory
* allocated for its stri